home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload Trio 2 / Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO / dir35 / cff51b.zip / PORTS / CFPORT.EMX < prev    next >
Text File  |  1993-10-22  |  16KB  |  780 lines

  1. /* CFPORT.EMX */
  2. /* PORTABILITY FOR CFF -- MODIFY TO SUIT THE COMPILER/OS IN USE */
  3.  
  4. #define INCL_BASE
  5. #define INCL_DOSMEMMGR
  6. #include <os2.h>
  7. #include <sys/types.h>
  8. #include <sys/stat.h>
  9. #include <stdlib.h>
  10. #include <fcntl.h>
  11. #include <errno.h>
  12. #include <time.h>
  13. #include <io.h>
  14. #include <share.h>
  15. #include <stdio.h>
  16. #include <dirent.h> 
  17. #include <dos.h>
  18. #include "..\cff.h"
  19.  
  20. extern void *mymemmove(void *, void *, long);
  21.  
  22. #define PCDOS 0    /* EMX CRASHES WHEN _int86 is used with -ac. Why?? */
  23.  
  24. #ifndef HAS_NO_SBRK
  25. #define HAS_NO_SBRK 0
  26. #endif
  27.  
  28. #define NIBBLE 128
  29. #define CHUNK_SIZE 8192
  30.  
  31. #ifndef HEAPSTART
  32. #define HEAPSTART 0x02100000
  33. #endif
  34.  
  35. int heapcreep;
  36. void *heapstart = (void *)HEAPSTART;
  37.  
  38.  
  39. static STOR BIGZERO;
  40.  
  41.  
  42. /* DUMMY ROUTINES TO PREVENT LINKING UNWANTED MALLOC LIKE STUFF */
  43. int _heapchk(void)
  44. {
  45.     return 0;
  46. }
  47.  
  48. int _heapset(unsigned a)
  49. {
  50.     return 0;
  51. }
  52. void *_expand (void *mem, size_t new_size)
  53. {
  54.     return NULL;
  55. }
  56. size_t _msize (const void *mem)
  57. {
  58.     return mallocsize(mem);
  59. }
  60.  
  61. /* ----------------- END OF MALLOC DUMMYS -------------------- */
  62.  
  63. static __inline__ unsigned long
  64. round_up(long size, long amt)
  65. {
  66.     return (size&(amt-1)) ? size+(amt-(size&(amt-1))) : size;
  67. }
  68.  
  69.  
  70.  
  71. static int testflags = 0;
  72. void
  73. cfport_settestflags(int flags)
  74. {
  75.     testflags |= flags;
  76. }
  77. void
  78. cfport_clrtestflags(int flags)
  79. {
  80.     testflags &= ~flags;
  81. }
  82.  
  83. static void
  84. fix_statbuf(struct stat *stat, CFSTAT *sbuf)
  85. {
  86.     sbuf->st_atime = stat->st_atime;
  87.     sbuf->st_mtime = stat->st_mtime;
  88.     sbuf->st_ctime = stat->st_ctime;
  89.     sbuf->st_size = stat->st_size;
  90.     sbuf->st_alloc = stat->st_size;
  91.     sbuf->st_filesize = stat->st_size;
  92.     sbuf->st_filealloc = stat->st_size;
  93. #if 0
  94.     sbuf->st_blksize = stat->st_blksize;
  95. #else
  96.     sbuf->st_blksize = 8192;
  97. #endif
  98.     sbuf->st_dev = stat->st_dev;
  99.     sbuf->st_ino = stat->st_ino;
  100.     sbuf->st_nlink = stat->st_nlink;
  101.     sbuf->st_uid = stat->st_uid;
  102.     sbuf->st_gid = stat->st_gid;    
  103.     sbuf->st_rdev = stat->st_rdev;
  104.     sbuf->st_mode = stat->st_mode;
  105. }
  106. #if HAS_NO_SBRK == 1
  107. static int sbrk_initted = 0;
  108. void *sbrkmem_base = NULL;
  109. static unsigned long mem_alloced = 0;
  110. static unsigned long sbrk_alloced = 0;
  111.  
  112. static int
  113. get_os2_memory(void)
  114. {
  115. void *my_base;
  116. unsigned long my_alloced;
  117.  
  118.     /* Allocate 32 Megabytes of uncommitted memory -- this is the OS2 limit */
  119.     my_alloced = 32*1024*1024;
  120.     while(DosAllocMem(&my_base, my_alloced, PAG_READ|PAG_WRITE))
  121.     {/* Failure -- try smaller allocation */
  122.         if(my_alloced <= 4*1024*1024)
  123.                 return 0;
  124.         my_alloced -= 4*1024*1024;
  125.     }
  126.     /* Check coalesce */
  127.     if(my_base == ((char *)sbrkmem_base + mem_alloced))
  128.         mem_alloced += my_alloced;
  129.     else
  130.     {
  131.         sbrkmem_base = my_base;
  132.         mem_alloced = my_alloced;
  133.         sbrk_alloced = 0;
  134.     }
  135.     return 1;
  136. }
  137.  
  138. void *sbrk(int amount)
  139. {
  140. int commit = 1;
  141.     if(!sbrk_initted)
  142.     {
  143.         if(!get_os2_memory())
  144.             abort(); 
  145.         sbrk_initted = 1;
  146.     }
  147. /*
  148.     OS2 Memory management is utterly terrible and stupid, memory should be
  149.     committed only when it is ACCESSED for the first time, and even then
  150.     it should not be allocated to pages in the swap file until swapping
  151.     of a particular page is required.
  152. */
  153.     if(amount < 0)
  154.     {
  155.         amount = -amount;
  156.         commit = 0;
  157.     }
  158.     for(;;)
  159.     {
  160.         if((amount + sbrk_alloced) <= mem_alloced)
  161.         {
  162.         void *return_base = (char *)sbrkmem_base + sbrk_alloced;
  163.             sbrk_alloced += amount;
  164.             if(commit)
  165.                 DosSetMem(return_base, amount, PAG_COMMIT|PAG_READ|PAG_WRITE);
  166.             return return_base;
  167.         }
  168.         if(!get_os2_memory())
  169.             return ((void *)-1);
  170.     }
  171. }
  172. #endif
  173. void *
  174. PORTSBRK(unsigned long amt)
  175. {
  176.     return sbrk(amt);
  177. }
  178. void
  179. PORTHEAPSTART(void)
  180. {
  181. void *curstart = sbrk(0);
  182. char *nextstart = NULL;
  183. unsigned long zone;
  184.  
  185.     if(curstart > heapstart)
  186.     {
  187.         cfprintf("CFPORT: The heap safety zone was exceeded by %d bytes.\n",
  188.             -((long)(heapstart - curstart)));
  189.         cfprintf("        Modify 'heapstart' in cfport.c\n");
  190.  
  191. #if HAS_NO_SBRK == 1
  192.         cfprintf("        sbrkmem_base=0x%lx=%lu sbrk_alloc=%lu\n",
  193.         sbrkmem_base, sbrkmem_base, mem_alloced);
  194. #endif
  195.         exit(-1);
  196.     }
  197.     zone = heapcreep = (unsigned long)(heapstart - curstart);
  198.     while(zone != 0)
  199.     {
  200.     int amount;
  201.     char *newstart;
  202.  
  203.         if(zone > 1024*1024)
  204.              amount = 1024*1024;
  205.         else amount = zone;
  206.  
  207. #if HAS_NO_SBRK == 1
  208.         newstart = sbrk(-amount);    /* Don't commit the memory */
  209. #else
  210.         newstart = sbrk(amount);
  211. #endif
  212.         if(newstart == (void *)-1) {
  213.             cfprintf("Failed to set heap: zone=%lu HSTART=%p cstart=%p left=%lu.\n",
  214.             heapcreep, heapstart, curstart, zone);
  215.             exit(-2);
  216.         }
  217.         zone -= amount;
  218.         nextstart = newstart + amount;
  219.     }
  220.     if(heapcreep && nextstart != heapstart) {
  221.         cfprintf("Heap was not set properly: desired=%p result=%p zone=%lu\n", 
  222.             heapstart, nextstart, heapcreep);
  223.         exit(-3);
  224.     }
  225. }
  226. int
  227. PORTSTAT(void *path, CFSTAT *sbuf)
  228. {
  229. struct stat _stat;
  230. int result = stat(path, &_stat);
  231.     if(result == 0)
  232.         fix_statbuf(&_stat, sbuf);
  233.     return result;
  234. }
  235. void
  236. PORTFSTAT(int handle, CFSTAT *sbuf)
  237. {
  238. struct stat stat;
  239.  
  240.     fstat(handle, &stat);
  241.     fix_statbuf(&stat, sbuf);    
  242. }
  243.  
  244. long
  245. PORTREAD(long handle, void *mem_addr, STOR dsk_addr, long amount)
  246. {
  247.     lseek(handle, dsk_addr.a0, SEEK_SET);  
  248.     return read(handle, mem_addr, amount);
  249.  
  250. }
  251. long
  252. PORTWRITE(long handle, void *mem_addr, STOR dsk_addr, long amount)
  253. {
  254.     lseek(handle, dsk_addr.a0, SEEK_SET);  
  255.     return write(handle, mem_addr, amount);
  256. }
  257. void
  258. PORTSEEK(long handle, STOR spot, int mode, STOR *loc)
  259. {
  260. STOR ret;
  261.     switch(mode)
  262.     {
  263.         case S_END:
  264.             mode = SEEK_END;
  265.             break;
  266.         case S_CUR:
  267.             mode = SEEK_CUR;
  268.             break;
  269.         case S_SET:
  270.             mode = SEEK_SET;
  271.             break;
  272.         default:
  273.             mode = -1;
  274.     }
  275.     ret.a4.s1 = 0;
  276.     ret.a4.s0 = lseek((int)handle, spot.a0, mode);
  277.     if(loc)
  278.         *loc = ret;
  279. }
  280. long
  281. PORTOPEN(void *path, int mode)
  282. {
  283. int omode = O_BINARY;
  284.  
  285.     if(mode & F_STAT)
  286.         omode |= O_RDONLY;
  287.     else if((mode & F_RDWR) == F_RDWR)
  288.         omode |= O_RDWR;
  289.     else if((mode & F_RDWR) == F_WRONLY)
  290.         omode |= O_RDWR;
  291.     else if((mode & F_RDWR) == F_RDONLY)
  292.         omode |= O_RDONLY;
  293.     if(mode & F_TRUNC)
  294.         omode |= O_TRUNC;
  295.     if(mode & F_EXCL)
  296.         omode |= O_EXCL;
  297.     if(mode & F_APPEND)
  298.         omode |= O_APPEND;
  299.  
  300.     return open(path,omode);
  301. }
  302. long
  303. PORTCLOSE(long handle)
  304. {
  305.     return close((int)handle);
  306. }
  307. long
  308. PORTCREATE(void *path, int mode)
  309. {
  310. int shflg;
  311.     if(mode & F_EXCL)
  312.          shflg = SH_DENYRW;
  313.     else shflg = SH_DENYNO;
  314.     return sopen(path,O_BINARY|O_CREAT|O_TRUNC|O_RDWR,shflg,S_IREAD|S_IWRITE);
  315. }
  316. long
  317. PORTUNLINK(void *path)
  318. {
  319.     return unlink(path);
  320. }
  321. #if PCDOS == 1
  322. static void
  323. dos_truncate(short handle, long amount)
  324. {
  325. #include <dos.h>
  326. union REGS r;
  327.  
  328.     r.h.al = 0;        /* SEEK_SET */
  329.     r.h.ah = 0x42;    /* seek */
  330.     r.x.bx = handle;
  331.     r.x.dx = (short)amount;
  332.     r.x.cx = (short)(amount>>16);
  333.     _int86(0x21,&r,&r);
  334.  
  335.     r.h.ah = 0x40;    /* write */
  336.     r.x.bx = handle;
  337.     r.x.cx = 0;        /* amount == 0 */
  338.     _int86(0x21,&r,&r);
  339.     
  340.     r.h.ah = 0x3e;    /* close */
  341.     r.x.bx = handle;
  342.     _int86(0x21,&r,&r);
  343. }
  344. #endif
  345. long
  346. PORTTRUNCATE(long handle, char *path, STOR amount)
  347. {
  348. #if PCDOS == 1
  349.     if(_emx_env & 0x200)
  350.     {/* Running under OS2 */
  351.         ftruncate((int)handle, amount.a0);
  352.         return handle;
  353.     }
  354.     else
  355.     {/* This isnt necessary, EMX can truncate a a DOS file, DJCC cannot. */
  356.         dos_truncate((short)handle, amount.a0);
  357.         return PORTOPEN(path, F_RDWR);
  358.     }
  359. #else
  360.     ftruncate((int)handle, amount.a0);
  361.     return handle;
  362. #endif
  363. }
  364. void
  365. PORTCLOSETRUNC(long handle, STOR amount)
  366. {
  367. #if PCDOS == 1
  368.     if(_emx_env & 0x200)
  369.     {/* Running under OS2 */
  370.         ftruncate((int)handle, amount.a0);
  371.         close ((int)handle);
  372.     }
  373.     else
  374.         dos_truncate((short)handle, amount.a0);
  375. #else
  376.     ftruncate((int)handle, amount.a0);
  377.     close((int)handle);
  378. #endif
  379. }
  380. static __inline__ void 
  381. sync(void)
  382. {/* EMX doesn't know about sync */
  383. }
  384. void
  385. PORTFLUSH(long handle)
  386. {
  387.     if(handle < 0)
  388.          sync();
  389.     else fsync((int)handle);
  390. }
  391.  
  392. char *
  393. PORTGETCWD(void *buf, int maxlen)
  394. {
  395. char *result;
  396.  
  397.     result = getcwd((char *)buf, maxlen);
  398.     ((char *)buf)[maxlen] = 0;
  399.     if(result)
  400.     {
  401.         while(*((char *)buf))
  402.         {
  403.             if(*((char *)buf) == '\\') *((char *)buf) = '/';
  404.             ++((char *)buf);
  405.         }
  406.     }
  407.     return result;
  408. }
  409.  
  410. long
  411. PORTCHDIR(void *path)
  412. {
  413.     return chdir(path);
  414. }
  415. unsigned long
  416. PORTTIME(void)
  417. {
  418.     return time(NULL);
  419. }
  420. unsigned long
  421. PORTCLOCK(void)
  422. {
  423.     return clock();
  424. }
  425. volatile void
  426. PORTABORT(void)
  427. {
  428. extern volatile void abort();
  429.     abort();
  430. }
  431.  
  432. /* THE BASIC OS DRIVERS */
  433.  
  434. /* Primary Memory driver */
  435. long
  436. pmem_driver(int func, int handle, void *mem_addr, STOR dsk_addr, long amount)
  437. {
  438.     switch(func)
  439.     {
  440.         case    S_GETSPACE:
  441.         {
  442.         unsigned long min, nib, current;
  443.  
  444.             amount = round_up(amount, CHUNK_SIZE);
  445.             min = round_up(amount / 4, CHUNK_SIZE);
  446.             nib = round_up(amount / 16, CHUNK_SIZE);
  447.             current = amount;
  448.             ((STOR *)mem_addr)->a2.size = 0;
  449.             ((STOR *)mem_addr)->a2.type = STO_CHUNK;
  450.  
  451.             while(current >= min) {
  452.               if((((STOR *)mem_addr)->a1 = PORTSBRK(current)) != (void *)-1) {
  453.                 if(((STOR *)mem_addr)->a0 & (NIBBLE-1))
  454.                 {/* Normally the system uses NIBBLE bytes as the alignment */
  455.                   ((STOR *)mem_addr)->a0 = 
  456.                               round_up(((STOR *)mem_addr)->a0, NIBBLE);
  457.                   current -= NIBBLE;
  458.                 }
  459.                 ((STOR *)mem_addr)->a2.size = current;
  460.                 return 0;
  461.               }
  462.               current -= nib;
  463.             }
  464.             return 1;
  465.         }
  466.         case    S_GIVESPACE:
  467.             return 1;
  468.         default:
  469.             return 1;
  470.     }
  471.     return 0;
  472. }
  473.  
  474. /* Secondary Memory driver */
  475. long
  476. smem_driver(int func, int handle, void *mem_addr, STOR dsk_addr, long amount)
  477. {
  478.     if(!(testflags & 1))
  479.     {/* 
  480.         IF SECONDARY MEMORY REALLY EXISTS, THEN PUT A REAL DRIVER HERE.
  481.         The system adapts to a 0 return from S_GETSPACE by mapping 
  482.         secondary memory to primary memory when cfinit is called.
  483.         S_OPEN is never called.
  484.      */
  485.         switch (func)
  486.         {
  487.             case S_GETSPACE:
  488.                 *((long *)mem_addr) = 0;
  489.                 break;
  490.         }
  491.         return -1;
  492.     } /* END: Real driver */
  493.     else {
  494.     /* THIS CODE IS JUST FOR TESTING PURPOSES, IT USES A LOCAL MEMORY BUFFER */
  495.  
  496. #define SMEMMAX (4096*1024)
  497. static char *sbuf = NULL;
  498. static long smemalloc = 0;
  499.  
  500.         if(sbuf == NULL) {
  501.             if((sbuf = PORTSBRK(SMEMMAX)) == (void *)-1) {
  502.                 cfprintf("SMEM_DRIVER: Failed to init test memory block.\n");
  503.                 exit(-1);
  504.             }
  505.         }
  506.         switch(func)
  507.         {
  508.             case    S_CLOSE:
  509.                 return 0;        /* a real driver would do something */            
  510.             case    S_READBLK:
  511.             case    S_WRITEBLK:
  512.             {
  513.             char *smemaddr = sbuf + dsk_addr.a0;
  514.             long xfer = amount;
  515.                 if(dsk_addr.a0 + amount > smemalloc)
  516.                     xfer = smemalloc - dsk_addr.a0;
  517.                 if(xfer < 0) {
  518.                     return -1;
  519.                 }
  520.                 if(func == S_READBLK)
  521.                      mymemmove(mem_addr, smemaddr, xfer);
  522.                 else mymemmove(smemaddr, mem_addr, xfer);
  523.                 return xfer;
  524.             }
  525.             case    S_GETSPACE:
  526.                 amount = round_up(amount, CHUNK_SIZE);
  527.                 ((STOR *)mem_addr)->a0 = smemalloc;
  528.                 ((STOR *)mem_addr)->a2.size = 0;
  529.                 ((STOR *)mem_addr)->a2.type = STO_CHUNK;
  530.                 if(amount + smemalloc < SMEMMAX) {
  531.                     ((STOR *)mem_addr)->a2.size = amount;
  532.                     smemalloc += amount;
  533.                     return 0;
  534.                 } else {/* Not enough space available, return error + avail */
  535.                     ((STOR *)mem_addr)->a2.size = 
  536.                                     (SMEMMAX - smemalloc) & ~CHUNK_SIZE;
  537.                     return 1;
  538.                 }
  539.             case    S_GIVESPACE:
  540. #if 0
  541. cfprintf("SMEM: GIVESPACE at loc=%lx size=%lu curbase=%lx\n",
  542. ((STOR *)mem_addr)->a0, ((STOR *)mem_addr)->a2.size, smemalloc);
  543. #endif
  544.                 if(((STOR *)mem_addr)->a0 == 
  545.                         smemalloc - ((STOR *)mem_addr)->a2.size)
  546.                 {/* Accept returns if they are at the end */
  547.                     smemalloc -= ((STOR *)mem_addr)->a2.size;
  548. #if 0
  549. cfprintf("SMEM: Truncate to %lu bytes\n", smemalloc);
  550. #endif
  551.                     return 0;
  552.                 }
  553.                 break;
  554.             default:
  555.                 break;
  556.         }
  557.         return 1;
  558.     }/* END: test driver */
  559. }
  560.  
  561. /* Internal file driver */
  562. long
  563. cfile_driver(int func, int handle, void *mem_addr, STOR dsk_addr, long amount)
  564. {
  565. long result = 0;
  566.  
  567.     switch(func)
  568.     {
  569.         case S_READBLK:
  570.             result = PORTREAD(handle, mem_addr, dsk_addr, amount);
  571.             break;
  572.         case S_WRITEBLK:
  573.             result = PORTWRITE(handle, mem_addr, dsk_addr, amount);
  574.             break;
  575.         case    S_GETSPACE:
  576.         {
  577.         unsigned long result;
  578.         STOR base;
  579.         STOR end;
  580.             PORTSEEK(handle, BIGZERO, S_END, &base);
  581.             amount = round_up(amount, CHUNK_SIZE);
  582.             end.a4.s0 = base.a0 + amount-1;
  583.             end.a4.s1 = 0;
  584.             PORTWRITE(handle, "0", end, 1);
  585.             PORTSEEK(handle, BIGZERO, S_END, &end);
  586.             result = end.a0 - base.a0;
  587.             ((STOR *)mem_addr)->a0 = base.a0;
  588.             ((STOR *)mem_addr)->a2.size = result;
  589.             ((STOR *)mem_addr)->a2.type = STO_CHUNK;
  590.             return (result == amount) ? 0:1;        
  591.         }
  592.         case    S_GIVESPACE:
  593.         {
  594.         STOR base;
  595.             PORTSEEK(handle, BIGZERO, S_END, &base);
  596.             if((((STOR *)mem_addr)->a0 + ((STOR *)mem_addr)->a2.size) == base.a0)
  597.             {/* OK to return space if at end */
  598. #if 0
  599.             long result;
  600.                 base.a0 -= ((STOR *)mem_addr)->a2.size;
  601.                 result = PORTTRUNCATE(handle, base);
  602. #endif
  603.                 return 0;
  604.             }
  605.             else return 1;
  606.         }
  607.         case    S_OPEN:
  608.             result = PORTOPEN(mem_addr, handle);
  609.             break;
  610.         case    S_CLOSE:
  611.             result = PORTCLOSE(handle);
  612.             break;
  613.         case    S_CREATE:
  614.             result = PORTCREATE(mem_addr, handle);
  615.             break;
  616.         case    S_UNLINK:
  617.             result = PORTUNLINK(mem_addr);
  618.             break;
  619.         case    S_SEEK:
  620.             PORTSEEK(handle, dsk_addr, amount, mem_addr);
  621.             break;
  622.         case    S_FLUSH:
  623.             PORTFLUSH(handle);
  624.             break;
  625.         case    S_CLOSETRUNC: /* truncate and close, (PCDOS needs this) */
  626.             PORTCLOSETRUNC(handle, dsk_addr);
  627.             break;
  628.         default:
  629.             return 1;
  630.     }
  631.     return result;
  632. }
  633. /* External file driver */
  634. long
  635. xfile_driver(int func, int handle, void *mem_addr, STOR dsk_addr, long amount)
  636. {
  637. long result = 0;
  638.  
  639.     switch(func)
  640.     {
  641.         case    S_GETSPACE:
  642.             ((STOR *)mem_addr)->a2.size = 0;
  643.         case    S_GIVESPACE:
  644.             return 1;
  645.         case    S_OPEN:
  646.             result = PORTOPEN(mem_addr, handle);
  647.             break;
  648.         case    S_CLOSE:
  649.             result = PORTCLOSE(handle);
  650.             break;
  651.         case    S_UNLINK:
  652.             result = PORTUNLINK(mem_addr);
  653.             break;
  654.         case    S_CREATE:
  655.             result = PORTCREATE(mem_addr,handle);
  656.             break;
  657.         case    S_READBLK:
  658.             result = PORTREAD(handle, mem_addr, dsk_addr, amount);
  659.             break;
  660.         case    S_WRITEBLK:
  661.             result = PORTWRITE(handle, mem_addr, dsk_addr, amount);
  662.             break;
  663.         case    S_SEEK:
  664.             PORTSEEK(handle, dsk_addr, amount, mem_addr);
  665.             break;
  666.         case    S_FLUSH:
  667.             PORTFLUSH(handle);
  668.             break;
  669.         default:
  670.             return 1;
  671.     }
  672.     return result;
  673. }
  674. void *
  675. PORTOPENDIR(char *name)
  676. {
  677.     return opendir(name);
  678. }
  679. void *
  680. PORTREADDIR(void *it, CFDIRENT *d)
  681. {
  682. struct dirent *rd;
  683.     if((rd = readdir(it))) {
  684.         d->d_namlen = rd->d_namlen;
  685.         d->d_name = rd->d_name;
  686.         d->d_mode = M_EXTRNFILE;
  687.     }
  688.     return rd;
  689. }
  690. void
  691. PORTTELLDIR(void *it, STOR *loc)
  692. {
  693. STOR me;
  694.     me.item = 0;
  695.     me.a0 = telldir(it); 
  696.     if(loc)
  697.         *loc = me;
  698. }
  699. void
  700. PORTSEEKDIR(void *it, STOR *loc)
  701. {
  702.     seekdir(it, loc->a0);
  703. }
  704. void
  705. PORTREWINDDIR(void *it)
  706. {
  707.     rewinddir(it);
  708. }
  709. long
  710. PORTCLOSEDIR(void *it)
  711. {
  712.     return closedir(it);
  713. }
  714. int
  715. PORTPRINT(int c)
  716. {
  717.     return write(1, &c, 1);
  718. }
  719.  
  720. #if 0
  721. /* 
  722.     THIS CODE IS FOR SAMPLE PURPOSES ONLY -- THE REAL CODE IS IN THE LIBRARY
  723.     PROGRAMMERS WHO WISH TO CREATE CUSTOM COMPARISON ROUTINES CAN USE THESE
  724.     FUNCTIONS AS MODELS.
  725. */
  726. /*
  727.     default_keycmp - system key comparison
  728.  
  729.     Return:    LESS    if keya <  keyb
  730.             EQUAL    if keya == keyb
  731.             GREATER    if keya >  keyb
  732. */
  733. static __inline__ int
  734. mymemcmp(unsigned char *a, unsigned char *b, int len)
  735. {
  736. int result = 0;
  737.     do {
  738.         if((result = ((int)*a++) - ((int)*b++)))
  739.             return result;
  740.     } while(--len);
  741.     return result;
  742. }
  743. int
  744. default_keycmp (void *keya, int    lena, void *keyb, int lenb)
  745. {
  746. int    result;
  747.  
  748.     if (lena == 0)
  749.         return ( (lenb == 0) ? EQUAL : LESS );
  750.     else if (lenb == 0)
  751.         return (GREATER);
  752.  
  753.  
  754.     result = mymemcmp (keya, keyb, ((lena<lenb)?lena:lenb));
  755.  
  756.     if (result < 0)
  757.         return LESS;
  758.     if (result > 0)
  759.         return GREATER;
  760.  
  761.     return ((lena == lenb) ? EQUAL : ((lena < lenb) ? LESS : GREATER));
  762.  
  763. }
  764. /*
  765.     default_itemcmp - system item comparison
  766.  
  767.     Return:    LESS-1        if itema <  itemb
  768.             EQUAL+1        if itema == itemb
  769.             GREATER+1    if itema >  itemb
  770. */
  771.  
  772. int
  773. default_itemcmp (Item *a, Item *b)
  774. {
  775.     return ( (a->item == b->item) ? 
  776.                 EQUAL+1 : ((a->item < b->item) ? LESS-1 : GREATER+1) );
  777. }
  778.  
  779. #endif
  780.